package controller

import (
	"go-pan/internal/utils"
	"net/http"
	"strconv"

	"go-pan/internal/service"

	"github.com/gin-gonic/gin"
)

type UploadHandler struct {
	UploadService service.UploadService
}

func (c *UploadHandler) InitUpload(ctx *gin.Context) {
	var req InitUploadRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		ctx.JSON(http.StatusBadRequest, ErrorResponse{Message: "Invalid request payload: " + err.Error()})
		return
	}

	userInfo, ok := utils.GetUserInfo(ctx)
	if !ok || userInfo == nil || userInfo.ID == 0 {
		ctx.JSON(http.StatusUnauthorized, ErrorResponse{Message: "Unauthorized: user info not found"})
		return
	}

	task, err := c.UploadService.InitUpload(ctx, req.FileName, req.FileSize, req.MimeType, userInfo.ID)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, ErrorResponse{Message: "Failed to initialize upload: " + err.Error()})
		return
	}

	ctx.JSON(http.StatusOK, task)
}

func (c *UploadHandler) UploadChunk(ctx *gin.Context) {
	uploadID, err := strconv.ParseInt(ctx.PostForm("upload_id"), 10, 64)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, ErrorResponse{Message: "Invalid upload ID"})
		return
	}

	chunkIndex, err := strconv.Atoi(ctx.PostForm("chunk_index"))
	if err != nil {
		ctx.JSON(http.StatusBadRequest, ErrorResponse{Message: "Invalid chunk index"})
		return
	}
	size, err := strconv.Atoi(ctx.Request.Header.Get("size"))
	if err != nil {
		ctx.JSON(http.StatusBadRequest, ErrorResponse{Message: "Invalid chunk size"})
		return
	}

	file, _, err := ctx.Request.FormFile("file")
	if err != nil {
		ctx.JSON(http.StatusBadRequest, ErrorResponse{Message: "No file uploaded"})
		return
	}

	// You might want to validate chunk size here against header.Size
	// and compare with the expected chunk size from the upload task

	err = c.UploadService.UploadChunk(ctx, uploadID, chunkIndex, int64(size), file)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, ErrorResponse{Message: "Failed to upload chunk"})
		return
	}

	ctx.JSON(http.StatusOK, SuccessResponse{Message: "Chunk uploaded successfully"})
}

func (c *UploadHandler) CompleteUpload(ctx *gin.Context) {
	uploadID, err := strconv.ParseInt(ctx.Param("upload_id"), 10, 64)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, ErrorResponse{Message: "Invalid upload ID"})
		return
	}

	// 从请求参数或请求体中获取客户端 hash
	clientHash := ctx.Query("hash")
	if clientHash == "" {
		// 尝试从请求体获取
		var req CompleteUploadRequest
		if err := ctx.ShouldBindJSON(&req); err == nil {
			clientHash = req.Hash
		}
	}

	err = c.UploadService.CompleteUpload(ctx, uploadID, clientHash)
	if err != nil {
		// You might want to handle different error types differently
		ctx.JSON(http.StatusBadRequest, ErrorResponse{Message: err.Error()})
		return
	}

	ctx.JSON(http.StatusOK, SuccessResponse{Message: "Upload completed successfully"})
}

func (c *UploadHandler) GetUploadStatus(ctx *gin.Context) {
	uploadID, err := strconv.ParseInt(ctx.Param("upload_id"), 10, 64)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, ErrorResponse{Message: "Invalid upload ID"})
		return
	}

	task, err := c.UploadService.GetUploadStatus(ctx, uploadID)
	if err != nil {
		ctx.JSON(http.StatusNotFound, ErrorResponse{Message: "Upload task not found"})
		return
	}

	ctx.JSON(http.StatusOK, task)
}

// Helper structs for request/response

type InitUploadRequest struct {
	FileName string `json:"file_name" binding:"required"`
	FileSize int64  `json:"file_size" binding:"required,gt=0"`
	MimeType string `json:"mime_type" binding:"required"`
}

type CompleteUploadRequest struct {
	Hash string `json:"hash"` // 客户端计算的流式 hash
}

type SuccessResponse struct {
	Message string `json:"message"`
}

type ErrorResponse struct {
	Message string `json:"message"`
}
